---
title: Roots
description: A guide on how to create and use the Root API
---

:::note[Psst, WebGPU veterans...]
You can think of roots as typed wrappers around WebGPU devices.
:::


Roots are responsible for resource allocation and management. Whether you'd like to wrap an existing WebGPU buffer
with a typed shell or create a brand new buffer, roots are the place to start.

You can create a root using the `tgpu.init` function.

```ts
const root = await tgpu.init();
```

It requests a GPU device with default requirements. An optional parameter
can be passed in with special requirements for the GPU device. If you already have a device that you want to use,
you can pass it into `tgpu.initFromDevice` instead.

```ts
const root = tgpu.initFromDevice({ device });
```

To retrieve the device that is associated with a root, you can use the `root.device` property.

```ts
const device = root.device; // => GPUDevice

context.configure({
  device,
  format: presentationFormat,
  alphaMode: 'premultiplied',
});
```

## Creating resources

Every `root.create*` function creates a typed resource.

| Function | Description |
| --- | --- |
| <div className="w-max">`root.createBuffer`</div> | Creates a typed buffer with a given data-type and, optionally, an initial value. More information in [the Buffers chapter](/TypeGPU/fundamentals/buffers). |

## Unwrapping resources

There are times where a typed resource needs to be used by a vanilla WebGPU API. To retrieve the raw
untyped value of a typed resource, use the `root.unwrap` function.

| Function | Description |
| --- | --- |
| `root.unwrap(resource: TgpuBuffer<AnyData>)` | Returns a `GPUBuffer`. |
| `root.unwrap(resource: TgpuBindGroupLayout)` | Returns a `GPUBindGroupLayout`. |
| `root.unwrap(resource: TgpuBindGroup)` | Returns a `GPUBindGroup`. |
| `root.unwrap(resource: TgpuVertexLayout)` | Returns a `GPUVertexBufferLayout`. |
{/* | `root.unwrap(resource: TgpuTexture)` | Returns a `GPUTexture`. | */}
{/* | `root.unwrap(resource: TgpuReadonlyTexture \| TgpuWriteonlyTexture \| TgpuMutableTexture \| TgpuSampledTexture)` | Returns a `GPUTextureView`. | */}

:::note
To unwrap a `TgpuVertexLayout` make sure to explicitly mark each of its attributes with the appropriate location using `d.location(...)`.
:::

## Destroying resources

Calling `root.destroy()` will call `device.destroy()` to let the browser know that it can free up all the resources. However, if an existing device is passed in via `tgpu.initFromDevice()`, this method does nothing.

```ts
root.destroy(); // <- frees up all the resources
```

## Best practices

Treat roots as their own separate universes, meaning resources created from the same root can interact with each other, while
resources created by seperate roots can have a hard time interacting. This usually means creating just one root at the start
of the program is the safest bet, but there are exceptions.

### If you do not own the GPU device

If you cannot control the lifetime of the GPU device you are to use for computing/rendering, but are instead given the device in a lifecycle hook (e.g., react-native-wgpu),
**you can create a new root each time, as long as you recreate every resource as well.**

```ts
// example.tsx
import React from 'react';

function SceneView() {
  const ref = useWebGPU(({ context, device, presentationFormat }) => {
    const root = tgpu.initFromDevice({ device });

    // create all resources...
  });

  // ...
}
```

### If you pass the GPU device everywhere

It is common practice to pass a `GPUDevice` to classes or functions for them to allocate their required resources. At first glance, this poses a problem when trying to
incorporate TypeGPU, since we would need to pass a root around instead of a device for all functionality that wants to move towards a typed API. **We can create a global mapping
between devices and roots to solve this.**

:::note
When designing an architecture from scratch with TypeGPU in mind, passing a `root` around instead of a `device` is the preferred pattern, since
`root.device` can act as an escape hatch for vanilla WebGPU functionality.
:::

You can copy and paste the utility below that implements a basic global cache for roots.

```ts
// roots.ts

const deviceToRootMap = new WeakMap<GPUDevice, TgpuRoot>();

function getOrInitRoot(device: GPUDevice): TgpuRoot {
  let root = deviceToRootMap.get(device);

  if (!root) {
    root = tgpu.initFromDevice({ device });
    deviceToRootMap.set(device, root);
  }

  return root;
}
```

If you reuse the same `getOrInitRoot` function across code that has to create resources, the root will be shared
across them.

```ts
class GameObject {
  constructor(device: GPUDevice) {
    const root = getOrInitRoot(device);

    // create all resources...
  }
}
```
